package cn.buk.api.ctrip.Factory;

import cn.buk.api.ctrip.dto.hotel.HotelRequestBody;
import cn.buk.api.ctrip.dto.tbooking.*;
import cn.buk.util.DateUtil;
import com.ctrip.openapi.java.utils.ConfigData;
import com.ctrip.openapi.java.utils.SignatureUtils;
import com.thoughtworks.xstream.XStream;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.SAXReader;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Date;

/**
 * Created by yfdai on 15/4/20.
 */
public class CreateRequestXmlFactory extends BaseFactory {

    private static final Logger logger = Logger.getLogger(CreateRequestXmlFactory.class);

    private static Element createRequestHeaderElement(String allianceId, String sid, String secretKey, Document document, String requestType) {
        Element returnElement = document.addElement("Request");
        Element element = returnElement.addElement("Header");
        element.addAttribute("AllianceID", allianceId);
        element.addAttribute("SID", sid);
        long timestamp = SignatureUtils.GetTimeStamp();
        String signature = null;
        try {
            signature = SignatureUtils.CalculationSignature(timestamp + "", allianceId, secretKey, sid, requestType);
        } catch (Exception e) {
        }
        element.addAttribute("TimeStamp",timestamp+"");
        element.addAttribute("Signature",signature);
        element.addAttribute("RequestType", requestType);

        return returnElement;
    }

    private static Element createRequestElement(HotelRequestBody requestBody) throws JAXBException {
        JAXBContext jc = JAXBContext.newInstance(HotelRequestBody.class);

        Marshaller m = jc.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
        m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);

        DocumentResult documentResult = new DocumentResult();
        m.marshal(requestBody, documentResult);

        return documentResult.getDocument().getRootElement();
    }

    /**
     * 生成根据条件搜索酒店基本信息的请求xml
     * @param requestBody
     * @param allianceId
     * @param sid
     * @param secretKey
     * @return
     * @throws JAXBException
     */
    public static String createOtaHotelSearchRequestXml(HotelRequestBody requestBody, String allianceId, String sid, String secretKey) throws JAXBException {
        Element requestElement = createRequestElement(requestBody);

        Element ele = requestElement.element("OTA_HotelSearchRQ");
        ele.addNamespace("", HOTEL_XML_NAMESPACE);

        org.dom4j.Document doc1 = DocumentHelper.createDocument();
        org.dom4j.Element rootElement = createRequestHeaderElement(allianceId, sid, secretKey, doc1, ConfigData.OTA_HotelSearch_Request);
        rootElement.add(requestElement);

        return doc1.asXML();
    }


    public static String createOtaHotelDetailRequestXml(HotelRequestBody requestBody, String allianceId, String sid, String secretKey) throws JAXBException {
        Element requestElement = createRequestElement(requestBody);

        Element ele = requestElement.element("OTA_HotelDescriptiveInfoRQ");
        ele.addNamespace("", HOTEL_XML_NAMESPACE);

        org.dom4j.Document doc1 = DocumentHelper.createDocument();
        org.dom4j.Element rootElement = createRequestHeaderElement(allianceId, sid, secretKey, doc1, ConfigData.OTA_HotelDetail_Request);
        rootElement.add(requestElement);

        return doc1.asXML();
    }

    public static String createHotelRequestBodyXml(HotelRequestBody requestBody, String requestType, String allianceId, String sid, String secretKey) throws JAXBException {
        Element requestElement = createRequestElement(requestBody);

        org.dom4j.Document doc1 = DocumentHelper.createDocument();
        org.dom4j.Element rootElement = createRequestHeaderElement(allianceId, sid, secretKey, doc1, requestType);
        rootElement.add(requestElement);

        return doc1.asXML();
    }

    public static String createOtaFlightSearchXml(String departCity, String arriveCity, Date departureDate, String requestType, String allianceId, String sid, String secretKey) {
        Document document = DocumentHelper.createDocument();
        Element rootElement = createRequestHeaderElement(allianceId, sid, secretKey, document, requestType);

        Element  body = rootElement.addElement("FlightSearchRequest");
        body.addElement("SearchType").setText("S");
        Element routesElement = body.addElement("Routes");
        Element routeElement = routesElement.addElement("FlightRoute");
        routeElement.addElement("DepartCity").setText(departCity);
        routeElement.addElement("ArriveCity").setText(arriveCity);
        routeElement.addElement("DepartDate").setText(DateUtil.formatDate(departureDate, "yyyy-MM-dd"));

        return document.asXML();
    }

    public static String createOtaUserUniqueIdRequestXml(String username, String requestType, String allianceId, String sid, String secretKey) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createRequestHeaderElement(allianceId, sid, secretKey, document, requestType);

        Element  body = rootElement.addElement("UserRequest");
        body.addElement("AllianceID").setText(allianceId);
        body.addElement("SID").setText(sid);
        body.addElement("UidKey").setText(username);

        return document.asXML();
    }

    public static Element createTBookingRootElement(final String username, final String password, final String md5password0, Document document)  {
        String md5password;

        if (md5password0 == null || md5password0.length() != 32)
            md5password = SignatureUtils.MD5(username + "#" + password);
        else
            md5password = md5password0;


        Element rootElement = document.addElement("Request");
        rootElement.addAttribute("UserName", username);
        rootElement.addAttribute("UserPassword", md5password);

        return rootElement;
    }

    public static String createTBookingOpenIssueOrderListRequestXml(String username, String password, final String md5password0, String beginTime, String endTime) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        Element element = rootElement.addElement("OpenIssueOrderListRequest");
        element.addElement("OrderBeginDateTime").setText(beginTime);
        if (endTime != null) {
            element.addElement("OrderEndDateTime").setText(endTime);
        }

        return document.asXML();
    }


    public static String createTBookingSearchIssueBillRequestXml(String username, String password, final String md5password0, String beginTime, String endTime, Long issueBillId) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        Element element = rootElement.addElement("OpenSearchIssueBillRequest");
        element.addElement("OrderBeginDateTime").setText(beginTime);
        element.addElement("OrderEndDateTime").setText(endTime);
        if (issueBillId == null) {
            element.addElement("IssueBillID").setText("0");
        } else {
            element.addElement("IssueBillID").setText(issueBillId.toString());
        }
//        element.addElement("IssueStatus").setText("");

        return document.asXML();
    }

    public static String createTBookingIssueBillInfoRequestXml(String username, String password, final String md5password0, long issueBillId) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        Element element = rootElement.addElement("OpenIssueBillInfoRequest");
        element.addElement("IssueBillID").setText(Long.toString(issueBillId));

        return document.asXML();
    }

    public static String createTBookingReconfirmTicketNoListRequestXml(String username, String password, final String md5password0) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        rootElement.addElement("OpenAbnormalTicketNORequest").setText("");

        return document.asXML();
    }

    public static String createTBookingSearchOrderDetailRequestXml(String username, String password, final String md5password0, int orderId) {
        Document document = DocumentHelper.createDocument();
        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        rootElement.addElement("OpenOrderDetailInfoRequest").addElement("OrderID").setText(Integer.toString(orderId));

        return document.asXML();
    }

    public static String createTBookingBackFillTicketNoRequestXml(String username, String password, final String md5password0, TBookingBackFillTicketNoRequest request) {
        Document document = DocumentHelper.createDocument();
        Element rootElement = createTBookingRootElement(username, password, md5password0, document);

        Element ele = rootElement.addElement("OpenModifyOrderRequest");
//        ele.addElement("OrderID").setText(Integer.toString(request.getOrderId()));
//        if (request.getIssueBillId() > 0)
        ele.addElement("IssueBillID").setText(Integer.toString(request.getIssueBillId()));

        Element elePnrLists = ele.addElement("PNRLists");

        for(PnrList pnrList: request.getPnrLists()) {
            Element elePnrList = elePnrLists.addElement("PNRList");
            elePnrList.addElement("Sequence").setText(Integer.toString(pnrList.getSequence()));
            elePnrList.addElement("PNRResultStatus").setText("1");
            if (pnrList.getPnr() != null && pnrList.getPnr().trim().length() > 0)
                elePnrList.addElement("PNR").setText(pnrList.getPnr());
            if (pnrList.getDport() != null && pnrList.getDport().trim().length() > 0)
                elePnrList.addElement("DPort").setText(pnrList.getDport());
            if (pnrList.getAport() != null && pnrList.getAport().trim().length() > 0)
                elePnrList.addElement("APort").setText(pnrList.getAport());

            Element eleTicketLists = elePnrList.addElement("TicketLists");
            for(TicketList ticketList: pnrList.getTicketLists()) {
                Element eleTicket = eleTicketLists.addElement("TicketList");

                eleTicket.addElement("PassengerName").setText(ticketList.getPsgName());
                eleTicket.addElement("AirLineCode").setText(ticketList.getAirlineCode());
                eleTicket.addElement("TicketNo").setText(ticketList.getTicketNo());
                eleTicket.addElement("TicketResultStatus").setText(ticketList.getTicketResultStatus() + "");
            }
        }

        return document.asXML();
    }

    /**
     * 出票单认领、取消认领
     * @param username
     * @param password
     * @param md5password
     * @param issueBillId 出票单ID
     * @param opType  0: 取消认领, 1: 认领
     * @return
     */
    public static String createTBookingIssueBillAssignToRequestXml(String username, String password, String md5password, long issueBillId, int opType) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password, document);

        Element element = rootElement.addElement("OpenIssueBillAssignRequest");
        element.addElement("IssueBillID").setText(Long.toString(issueBillId));
        element.addElement("OperatorType").setText(Integer.toString(opType));

        return document.asXML();
    }

    public static String createTBookingOpenUnpayOrderListRequestXml(String username, String password, String md5password, String beginTime) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password, document);

        Element element = rootElement.addElement("OpenUnpayOrderListRequest");
        element.addElement("OrderBeginDateTime").setText(beginTime);

        return document.asXML();
    }

    /**
     * PNR修改接口请求xml
     * @param username
     * @param password
     * @param md5password
     * @param rq
     * @return
     */
    public static String createTBookingOpenIssueBillModifyRequestXml(String username, String password, String md5password, IssueBillModifyRequest rq) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password, document);

        XStream xs = BaseFactory.createXStream(true);
        xs.processAnnotations(IssueBillModifyRequest.class);

        String xml = xs.toXML(rq);
        SAXReader reader = new SAXReader();
        Document document1 = null;
        try {
            // 统一编码，防止出错
            document1 = reader.read(new ByteArrayInputStream(xml.getBytes("UTF-8")));
        } catch (DocumentException | UnsupportedEncodingException ex) {
            logger.error(ex.getMessage());
            return null;
        }

        rootElement.add(document1.getRootElement());

        return document.asXML();
    }

    /**
     * PNR授权接口请求xml
     * @param username
     * @param password
     * @param md5password
     * @param rq
     * @return
     */
    public static String createTBooking_GetPnrPermission_RequestXml(String username, String password, String md5password, GetPnrPermissionRequest rq) {
        Document document = DocumentHelper.createDocument();

        Element rootElement = createTBookingRootElement(username, password, md5password, document);

        XStream xs = BaseFactory.createXStream(true);
        xs.processAnnotations(GetPnrPermissionRequest.class);

        String xml = xs.toXML(rq);
        SAXReader reader = new SAXReader();
        Document document1 = null;
        try {
            // 统一编码，防止出错
            document1 = reader.read(new ByteArrayInputStream(xml.getBytes("UTF-8")));
        } catch (DocumentException | UnsupportedEncodingException ex) {
            logger.error(ex.getMessage());
            return null;
        }

        rootElement.add(document1.getRootElement());

        return document.asXML();
    }
}
